use std::collections::HashMap;

use crate::{renderer, tag, transform};

pub trait ISystem<C> {
    fn components(&self) -> &HashMap<usize, C>;
    fn components_mut(&mut self) -> &mut HashMap<usize, C>;

    fn register(&mut self, entity_id: usize, component: C) {
        self.components_mut().insert(entity_id, component);
    }

    fn unregister(&mut self, entity_id: usize) {
        self.components_mut().remove(&entity_id);
    }

    fn component(&self, entity_id: usize) -> Option<&C> {
        self.components().get(&entity_id)
    }

    fn component_mut(&mut self, entity_id: usize) -> Option<&mut C> {
        self.components_mut().get_mut(&entity_id)
    }
}

pub struct Engine {
    id_cnt: usize,
    pub tags: tag::System,
    pub transforms: transform::System,
    pub renderers: renderer::System,
}

impl Engine {
    pub fn new() -> Self {
        Self {
            id_cnt: 0,
            tags: tag::System::new(),
            transforms: transform::System::new(),
            renderers: renderer::System::new(),
        }
    }

    pub fn create_entity(&mut self) -> usize {
        let id = self.id_cnt;
        self.id_cnt += 1;
        id
    }

    pub fn remove_entity(&mut self, entity_id: usize) {
        self.transforms.unregister(entity_id);
        self.renderers.unregister(entity_id);
    }

    pub fn entity_add_tag(&mut self, entity_id: usize, tag: tag::Component) {
        self.tags.register(entity_id, tag);
    }

    pub fn entity_add_transform(&mut self, entity_id: usize, transform: transform::Component) {
        self.transforms.register(entity_id, transform);
    }

    pub fn entity_add_renderer(&mut self, entity_id: usize, renderer: renderer::Component) {
        self.renderers.register(entity_id, renderer);
    }

    pub fn update(&mut self) {
        self.transforms.update();
        self.renderers.update(&self.tags, &self.transforms);
    }
}
